package s_service

import (
	"Infinichat_mixed/back/mapper"
	"Infinichat_mixed/entity"
	"Infinichat_mixed/global_utils"
	"Infinichat_mixed/server/s_utils"
	"encoding/json"
	"fmt"
	"github.com/google/uuid"
	"log"
	"strconv"
	"time"
)

func acquireLoginLock(uid uint, token string, ttl time.Duration) bool {
	key := "login_lock:" + strconv.Itoa(int(uid))
	ok, err := s_utils.RedisClient.SetNX(s_utils.Ctx, key, token, ttl).Result()
	if err != nil {
		fmt.Println("acquire login lock error:", err)
		return false
	}
	return ok
}

func ReleaseLoginLock(uid uint, token string) {
	fmt.Println("ReleaseLoginLock:", token)
	script := `
	if redis.call("get", KEYS[1]) == ARGV[1]
	then
		return redis.call("del", KEYS[1])
	else
		return 0
	end
	`
	key := "login_lock:" + strconv.Itoa(int(uid))
	_, err := s_utils.RedisClient.Eval(s_utils.Ctx, script, []string{key}, token).Result()
	if err != nil {
		fmt.Println("release login lock error:", err)
	}

}

func Login(account, password string) (user entity.User, token string, err error) {
	// 验证账号是否正确
	retUser := mapper.FindUserByAccount(account)
	if retUser.ID == 0 {
		// 账号不存在
		err = s_utils.ERROR_USER_NOTEXISTS
		return
	}
	// 拿到盐 进行解码
	salt := retUser.Salt
	pwd_inDB := global_utils.MakePassword(password, salt)
	ap := mapper.FindUserByAP(account, pwd_inDB)
	if ap.ID == 0 {
		// 密码错误
		err = s_utils.ERROR_USER_PWD
		return
	}
	// 分布式锁单点登录判断
	token = uuid.New().String()
	ok := acquireLoginLock(ap.ID, token, 60*time.Second)
	if !ok {
		return user, token, s_utils.ERROR_USER_LOGINED
	}
	return ap, token, nil
}

func GetFriend(val uint) []uint {
	friends := make([]entity.Friend, 0)
	err := s_utils.DB.Where("is_add = ? AND (sid = ? OR tid = ?)", true, val, val).Find(&friends).Error
	if err != nil {
		log.Println(err)
	}
	var result []uint
	for _, friend := range friends {
		if friend.Sid == val {
			result = append(result, friend.Tid)
		}
		if friend.Tid == val {
			result = append(result, friend.Sid)
		}
	}
	return result
}

func GetReq(id uint) (p2p_msg []entity.P2PMsg, p2m_msg []entity.P2MMsg, addIds []uint, gis []entity.GroupInvite, ret_err error) {
	var err error

	// 改成从rabbitmq中获取
	p2p_msg, _ = PullUnreadMsgsOnce(id)
	//p2p_msg, err = mapper.Unread_p2p(id)
	//if err != nil {
	//	fmt.Println(err)
	//	ret_err = err
	//}
	p2m_msg, err = mapper.Unread_p2m(id)
	if err != nil {
		fmt.Println(err)
		ret_err = err
	}
	addIds, err = mapper.FriendAddRequest(id)
	if err != nil {
		fmt.Println(err)
		ret_err = err
	}
	gis, err = mapper.GroupInviteNotify(id)
	if err != nil {
		fmt.Println(err)
		ret_err = err
	}
	return p2p_msg, p2m_msg, addIds, gis, ret_err
}

func PullUnreadMsgsOnce(userId uint) ([]entity.P2PMsg, error) {
	queue := fmt.Sprintf("p2p_unread_msg_%d", userId)
	ch, err := s_utils.MQ.Channel()
	if err != nil {
		return nil, err
	}
	defer ch.Close()
	var result []entity.P2PMsg
	for {
		msg, ok, err := ch.Get(
			queue,
			false,
		)
		if err != nil {
			return nil, err
		}
		if !ok {
			break
		}

		var unread entity.P2PMsg
		if err := json.Unmarshal(msg.Body, &unread); err == nil {
			result = append(result, unread)
		}
		_ = ch.Ack(msg.DeliveryTag, false)
	}
	return result, nil
}
